#pragma once
#include<string>
#include<string.h>
#include<memory>
#include<chrono>
#include<assert.h>
#include"LogStream.h"
#include"SourceFile.h"

namespace Log {
    class Logger
    {
    public:
        typedef void (*OutputFunc)(const char* msg, int len);
        typedef void (*FlushFunc)();

        enum LogLevel
        {
            TRACE,
            DEBUG,
            INFO,
            WARN,
            ERROR,
            FATAL,
            NUM_LOG_LEVELS,
        };

        static const char* LogLevelName[Logger::NUM_LOG_LEVELS];

        Logger(SourceFile file, int line);
        Logger(SourceFile file, int line, LogLevel level);
        Logger(SourceFile file, int line, LogLevel level, const char* func);
        Logger(SourceFile file, int line, bool toAbort);
        ~Logger();

        LogStream& stream() { return impl_.stream_; }
        static LogLevel logLevel(){ return g_logLevel; }
        static void setLogLevel(LogLevel level);
        static void setOutput(OutputFunc);
        static void setFlush(FlushFunc);

    private:

        class Impl
        {
        public:
            using LogLevel = Logger::LogLevel;
            Impl(LogLevel level, const SourceFile& file, int line);
            void finish();

            LogStream stream_;
            LogLevel level_;
            int line_;
            SourceFile basename_;
        };

        Impl impl_;
        static LogLevel g_logLevel;
        static OutputFunc g_output;
        static FlushFunc g_flush;

    };
#define LOG_TRACE if (Log::Logger::logLevel() <= Log::Logger::TRACE) \
    Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream()
#define LOG_DEBUG if (Log::Logger::logLevel() <= Log::Logger::DEBUG) \
    Logger(__FILE__, __LINE__, Logger::DEBUG, __func__).stream()
#define LOG_INFO if (Log::Logger::logLevel() <= Log::Logger::INFO) \
    Logger(__FILE__, __LINE__).stream()
#define LOG_WARN Logger(__FILE__, __LINE__, Logger::WARN).stream()
#define LOG_ERROR Logger(__FILE__, __LINE__, Logger::ERROR).stream()
#define LOG_FATAL Logger(__FILE__, __LINE__, Logger::FATAL).stream()
#define LOG_SYSERR Logger(__FILE__, __LINE__, false).stream()
#define LOG_SYSFATAL Logger(__FILE__, __LINE__, true).stream()
}
